package controller;

import com.jfinal.core.Controller;
import config.Constant;
import model.WechatCache;
import org.json.JSONObject;
import util.DateTimeUtils;
import util.HttpsRequest;
import util.SHA1;
import util.StringUtil;

import java.sql.Timestamp;
import java.util.UUID;

/**
 * Created by YL1988 on 2016/9/6 0006.
 */
public class WxController extends Controller {


    public static boolean CACHED = false;
    public static String CACHED_JSAPI_TICKET = null;
    public static Timestamp JSAPI_TICKET_EXPIRES = null;

    public static boolean CACHED2 = false;
    public static String CACHED_ACCESS_TOKEN = null;
    public static Timestamp ACCESS_TOKEN_EXPIRES = null;

    /**
     * JS-API config
     * Get the signature and return related information back
     */
    public void config() {
        JSONObject result = new JSONObject();
        String url = getPara("url");
        System.out.println("要签名的路径为："+url);

        if (StringUtil.isNullOrEmptyString(url, true)) {
            result.put("code", -1);
            result.put("msg", "路径错误");
        } else {
            url = url.trim().split("#")[0];
            String ticket = getJsapiTicket();
            System.out.println("ticket = "+ticket);
            String timestamp = create_timestamp();
            System.out.println("config timestamp = "+timestamp);
            String nonceStr = create_nonce_str().substring(0,31);
            System.out.println("config nonceStr = "+nonceStr);

            StringBuilder builder = new StringBuilder();
            builder.append("jsapi_ticket=").append(ticket)
                    .append("&noncestr=").append(nonceStr)
                    .append("&timestamp=").append(timestamp)
                    .append("&url=").append(url);

            String signature = new SHA1().getDigestOfString(builder.toString().getBytes()).toLowerCase();
            System.out.println("config signature = "+signature);
            result.put("code", 0);
            JSONObject body = new JSONObject();
            body.put("appId", Constant.APP_ID);
            body.put("timestamp", timestamp);
            body.put("nonceStr", nonceStr);
            body.put("signature", signature);
            result.put("body", body);

        }

       renderText(result.toString());
    }

    /**
     * Get Jsapi ticket
     * @return
     */
    public String getJsapiTicket() {
        // Attempt to get jsapi ticket from cache
        String ticket = getJsapiTicketFromCache();
        if (ticket != null) {
            System.out.println("有缓存，从缓存中读取");
            return ticket;
        }

        // attempt to get jsapi ticket from database
        System.out.println("没有缓存，从数据库中读取");
        ticket = getJsapiTicketFromDatabase();
        if (ticket != null) {
            return ticket;
        }

        // request jsapi ticket from wechat server
        System.out.println("数据库中也没有，从微信服务器获取");
        ticket = getJsapiTicketFromWechatServer();

        return ticket;
    }

    /**
     * Attempt to get jsapi ticket from cache
     * @return
     */
    private String getJsapiTicketFromCache() {
        // the jsapi ticket has been cached, token and expires are exist
        if (CACHED && CACHED_JSAPI_TICKET != null && JSAPI_TICKET_EXPIRES != null) {
            // and the cached ticket does not expires
            Timestamp now = DateTimeUtils.generateTimestamp();
            if (JSAPI_TICKET_EXPIRES.after(now)) {
                return CACHED_JSAPI_TICKET;
            }
        }

        // otherwise
        CACHED = false;
        return null;
    }

    /**
     * Attempt to get jsapi ticket from database
     * @return
     */
    private String getJsapiTicketFromDatabase() {
        // get last cache from database
        WechatCache cache = WechatCache.dao.findFirst("select * from wechat_cache");

        // if the ticket has been cached, token and expires are exist
        if (cache != null && cache.get("jsapi_ticket") != null && cache.getDate("jsapi_ticket_expires") != null) {
            // and the cached token does not expires
            Timestamp now = DateTimeUtils.generateTimestamp();
            System.out.println("now  = "+now);
            Timestamp temp = DateTimeUtils.generateTimestamp(cache.getDate("jsapi_ticket_expires"));
            System.out.println("数据库中的 jsapi_ticket_expires 时间戳为:"+ temp);
            if (temp.after(now)) {
                // update the ROM cache
                CACHED = false;
                CACHED_JSAPI_TICKET = cache.get("jsapi_ticket");
                JSAPI_TICKET_EXPIRES = temp;
                CACHED = true;

                // return the token
                return CACHED_JSAPI_TICKET;
            }
        }

        return null;
    }

    /**
     * Request access token from wechat server
     * @return
     */
    private String getJsapiTicketFromWechatServer() {
        String token = getAccessToken();
        if (token == null) {
            return null;
        }

        String ticket = null;

        // 构造参数
        StringBuilder builder = new StringBuilder();
        builder.append("access_token=").append(token.trim()).append("&type=jsapi");

        // 请求时间
        Timestamp now = DateTimeUtils.generateTimestamp();

        // 获取返回结果
        String response = null;
        try {
            response = HttpsRequest.sendGet(Constant.REQUEST_JSAPI_TICKET_URL, builder.toString());
        } catch (Exception e) {
            response = null;
        }

        // 处理返回结果
        if (response == null) {
            // 获取失败
            ticket = null;
        } else {
            // 解析返回数据
            JSONObject obj = new JSONObject(response);
            if (obj.has("ticket") && obj.has("expires_in")) {
                // 获取成功
                ticket = obj.getString("ticket");
                System.out.println("从服务器获取的jsapi_ticket为："+ticket);
                int expires = obj.getInt("expires_in");
                System.out.println("jsapi_ticket 过期时间为："+ new Timestamp(now.getTime() + expires * 1000));


                // 更新ROM Cache
                CACHED_JSAPI_TICKET = ticket;
                JSAPI_TICKET_EXPIRES = new Timestamp(now.getTime() + expires * 1000);
                CACHED = true;

                // 更新数据库Cache
                WechatCache.dao.findById(1).
                        set("jsapi_ticket", ticket).
                        set("jsapi_ticket_expires", new Timestamp(now.getTime() + expires * 1000)).
                        update();
            }
        }

        return ticket;
    }

    private static String create_timestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }

    private static String create_nonce_str() {
        return UUID.randomUUID().toString();
    }

    /**
     * 获取Access_token
     * @return
     */
    public String getAccessToken() {
        // Attempt to get access token from cache
        String token = getAccessTokenFromCache();
        if (token != null) {
            return token;
        }

        // attempt to get access token from database
        token = getAccessTokenFromDatabase();
        if (token != null) {
            return token;
        }

        // request access token from wechat server
        token = getAccessTokenFromWechatServer();
        return token;
    }

    /**
     * Attempt to get access token from cache
     * @return
     */
    public String getAccessTokenFromCache() {
        // the token has been cached, token and expires are exist
        if (CACHED2 && CACHED_ACCESS_TOKEN != null && ACCESS_TOKEN_EXPIRES != null) {
            // and the cached token does not expires
            Timestamp now = DateTimeUtils.generateTimestamp();
            if (ACCESS_TOKEN_EXPIRES.after(now)) {
                return CACHED_ACCESS_TOKEN;
            }
        }

        // otherwise
        CACHED2 = false;
        return null;
    }

    /**
     * Attempt to get access token from database
     * When get token successfully, update the cache
     * @return
     */
    private String getAccessTokenFromDatabase() {
        // get last cache from database
        WechatCache cache = WechatCache.dao.findFirst("select * from wechat_cache");

        // if the token has been cached, token and expires are exist
        if (cache != null && cache.get("access_token") != null && cache.getDate("access_token_expires") != null) {
            // and the cached token does not expires
            Timestamp now = DateTimeUtils.generateTimestamp();
            Timestamp temp = DateTimeUtils.generateTimestamp(cache.getDate("access_token_expires"));
            System.out.println("数据库中的 access_token_expires 时间戳为:"+ temp);
            if (temp.after(now)) {
                // update the ROM cache
                CACHED2 = false;
                CACHED_ACCESS_TOKEN = cache.get("access_token");
                ACCESS_TOKEN_EXPIRES = new Timestamp(cache.getDate("access_token_expires").getTime());
                CACHED2 = true;

                // return the token
                return CACHED_ACCESS_TOKEN;
            }
        }

        return null;
    }


    /**
     * Request access token from wechat server
     * @return
     */
    public String getAccessTokenFromWechatServer() {
        String token = null;

        // 构造参数
        StringBuilder builder = new StringBuilder();
        builder.append("grant_type=client_credential&")
                .append("appid=").append(Constant.APP_ID.trim()).append("&")
                .append("secret=").append(Constant.APP_SECRET.trim());

        // 请求时间
        Timestamp now = DateTimeUtils.generateTimestamp();

        // 获取返回结果
        String response = null;
        try {
            response = HttpsRequest.sendGet(Constant.ACCESS_TOKEN_URL, builder.toString());
        } catch (Exception e) {
            response = null;
        }

        // 处理返回结果
        if (response == null) {
            // 获取失败
            token = null;
        } else {
            // 解析返回数据
            JSONObject obj = new JSONObject(response);
            if (obj.has("access_token") && obj.has("expires_in")) {
                // 获取成功
                token = obj.getString("access_token");
                System.out.println("从微信获取的access_token为："+token);
                int expires = obj.getInt("expires_in");
                System.out.println("access_token 过期时间为："+ new Timestamp(now.getTime() + expires * 1000));

                // 更新ROM Cache
                CACHED_ACCESS_TOKEN = token;
                ACCESS_TOKEN_EXPIRES = new Timestamp(now.getTime() + expires * 1000);
                CACHED2 = true;

                // 更新数据库Cache
                WechatCache.dao.findById(1).
                        set("access_token", token).
                        set("access_token_expires", new Timestamp(now.getTime() + expires * 1000)).
                        update();

            }
        }

        return token;
    }

}
